package mylittleinvestigations;

import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.CaseInformation.Case;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import mylittleinvestigations.CaseInformation.CaseParseException;
import mylittleinvestigations.GameUi.Tab;
import mylittleinvestigations.GameUi.ButtonArray;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import mylittleinvestigations.EasingFunctions.*;
import mylittleinvestigations.Events.ButtonArrayEventProvider;
import mylittleinvestigations.Events.EvidenceSelectorEventProvider;
import mylittleinvestigations.Events.ButtonArrayEventListener;
import mylittleinvestigations.Events.EvidenceSelectorEventListener;
import mylittleinvestigations.GameUi.ButtonArrayLoadParameters;
import mylittleinvestigations.GameUi.TabRow;
import mylittleinvestigations.PersistentThreads.RenderThread;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

public class Encounter implements ButtonArrayEventListener, EvidenceSelectorEventListener
{
    private static final String ExitText = "EXIT";
    private static final String PresentEvidenceText = "PRESENT EVIDENCE";
    private static final String MainMenuHeaderText = "Talk About...";

    private static Image dialogBackgroundTexture;
    private static Image backgroundDarkeningTexture;

    private ArrayList<Conversation> conversationList;
    private ArrayList<Interrogation> interrogationList;
    private ArrayList<Confrontation> confrontationList;
    private ArrayList<Conversation> allConversationList;
    private HashMap<String, Conversation> presentEvidenceConversationDictionary;

    private ButtonArray mainMenuButtonArray;

    private ButtonArray nextButtonArray;
    private ButtonArray currentButtonArray;
    private ButtonArray lastButtonArrayBeforeConversation;
    private boolean shouldCloseButtonArray;

    private State state;
    private Conversation nextConversation;
    private Conversation currentConversation;

    private Tab exitTab;
    private Tab presentEvidenceTab;
    private EvidenceSelector evidenceSelector;

    private EasingFunction backgroundOpacityInEase;
    private EasingFunction dialogBackgroundInEase;
    private EasingFunction leftCharacterInEase;
    private EasingFunction rightCharacterInEase;
    private EasingFunction backgroundOpacityOutEase;
    private EasingFunction dialogBackgroundOutEase;
    private EasingFunction leftCharacterOutEase;
    private EasingFunction rightCharacterOutEase;

    private int backgroundOpacityAlphaValue;
    private int dialogBackgroundYPosition;

    public static void Initialize(Image dialogBackgroundTexture, Image backgroundDarkeningTexture) throws SlickException
    {
        Encounter.dialogBackgroundTexture = dialogBackgroundTexture;
        Encounter.backgroundDarkeningTexture = backgroundDarkeningTexture;
    }

    public Encounter()
    {
        this.conversationList = new ArrayList<Conversation>();
        this.interrogationList = new ArrayList<Interrogation>();
        this.confrontationList = new ArrayList<Confrontation>();
        this.presentEvidenceConversationDictionary = new HashMap<String, Conversation>();

        this.mainMenuButtonArray = new ButtonArray(MainMenuHeaderText);
        this.currentButtonArray = this.mainMenuButtonArray;

        this.exitTab = new Tab((int)Settings.DisplayBounds.getX() - Tab.Width, true /* isClickable */, ExitText);
        this.presentEvidenceTab = new Tab((int)Settings.DisplayBounds.getX() - 2 * Tab.Width - 7, true /* isClickable */, PresentEvidenceText);

        this.InitializeEasingFunctions();
    }

    private String id;

    public String getId() { return this.id; }
    public void setId(String id) { this.id = id; }

    private String initialLeftCharacterId;

    public String getInitialLeftCharacterId() { return this.initialLeftCharacterId; }
    public void setInitialLeftCharacterId(String initialLeftCharacterId) { this.initialLeftCharacterId = initialLeftCharacterId; }

    private String initialLeftCharacterEmotionId;

    public String getInitialLeftCharacterEmotionId() { return this.initialLeftCharacterEmotionId; }
    public void setInitialLeftCharacterEmotionId(String initialLeftCharacterEmotionId) { this.initialLeftCharacterEmotionId = initialLeftCharacterEmotionId; }

    private String initialRightCharacterId;

    public String getInitialRightCharacterId() { return this.initialRightCharacterId; }
    public void setInitialRightCharacterId(String initialRightCharacterId) { this.initialRightCharacterId = initialRightCharacterId; }

    private String initialRightCharacterEmotionId;

    public String getInitialRightCharacterEmotionId() { return this.initialRightCharacterEmotionId; }
    public void setInitialRightCharacterEmotionId(String initialRightCharacterEmotionId) { this.initialRightCharacterEmotionId = initialRightCharacterEmotionId; }

    private Conversation oneShotConversation;

    public Conversation getOneShotConversation() { return this.oneShotConversation; }
    public void setOneShotConversation(Conversation oneShotConversation) { this.oneShotConversation = oneShotConversation; }

    private Conversation presentWrongEvidenceConversation;

    public Conversation getPresentWrongEvidenceConversation() { return this.presentWrongEvidenceConversation; }
    public void setPresentWrongEvidenceConversation(Conversation presentWrongEvidenceConversation) { this.presentWrongEvidenceConversation = presentWrongEvidenceConversation; }

    private Conversation presentWrongProfileConversation;

    public Conversation getPresentWrongProfileConversation() { return this.presentWrongProfileConversation; }
    public void setPresentWrongProfileConversation(Conversation presentWrongProfileConversation) { this.presentWrongProfileConversation = presentWrongProfileConversation; }

    private boolean isFinished;

    public boolean getIsFinished() { return this.isFinished; }
    public void setIsFinished(boolean isFinished) { this.isFinished = isFinished; }
    
    private String initialConversationId;

    public String getInitialConversationId() { return this.initialConversationId; }
    public void setInitialConversationId(String initialConversationId) { this.initialConversationId = initialConversationId; }
    
    private String oneShotConversationId;

    public String getOneShotConversationId() { return this.oneShotConversationId; }
    public void setOneShotConversationId(String oneShotConversationId) { this.oneShotConversationId = oneShotConversationId; }

    public void AddConversation(Conversation conversation)
    {
        this.conversationList.add(conversation);
    }

    public void AddInterrogation(Interrogation interrogation)
    {
        this.interrogationList.add(interrogation);
    }

    public void AddConfrontation(Confrontation confrontation)
    {
        this.confrontationList.add(confrontation);
    }

    public void AddPresentEvidenceConversation(String evidenceId, Conversation conversation)
    {
        this.presentEvidenceConversationDictionary.put(evidenceId, conversation);
    }

    public void Begin()
    {
        if (this.evidenceSelector == null)
        {
            this.evidenceSelector = new EvidenceSelector(true /* isCancelable */);
        }

        this.Reset();

        this.state = new State();
        this.state.setLeftCharacterId(this.getInitialLeftCharacterId());
        this.state.setLeftCharacterEmotionId("Neutral");
        this.state.setRightCharacterId(this.getInitialRightCharacterId());
        this.state.setRightCharacterEmotionId("Neutral");

        this.backgroundOpacityAlphaValue = 0;
        this.dialogBackgroundYPosition = 195;

        this.state.setLeftCharacterXOffsetEasingFunction(this.leftCharacterInEase);
        this.state.setRightCharacterXOffsetEasingFunction(this.rightCharacterInEase);

        this.leftCharacterInEase.Begin();
        this.rightCharacterInEase.Begin();

        if (Utils.isNullOrEmpty(this.state.getLeftCharacterId()))
        {
            this.leftCharacterInEase.Finish();
        }

        if (Utils.isNullOrEmpty(this.state.getRightCharacterId()))
        {
            this.rightCharacterInEase.Finish();
        }

        this.backgroundOpacityInEase.Begin();
        this.dialogBackgroundInEase.Begin();
        
        ButtonArrayEventProvider.RegisterListener(this);
        EvidenceSelectorEventProvider.RegisterListener(this);

        if (this.getOneShotConversation() == null)
        {
            this.RefreshButtonArrays();
        }
        else
        {
            this.BeginConversation(this.getOneShotConversation());
        }

        this.setIsFinished(false);
    }

    public void Update(GameContainer gc, int delta) throws CaseParseException
    {
        boolean formattingAnimationInProgress = false;

        if (this.dialogBackgroundInEase.getIsStarted() && !this.dialogBackgroundInEase.getIsFinished())
        {
            this.dialogBackgroundInEase.Update(gc, delta);
            this.dialogBackgroundYPosition = (int)this.dialogBackgroundInEase.GetCurrentValue();
            formattingAnimationInProgress = true;
        }
        else if (this.dialogBackgroundOutEase.getIsStarted() && !this.dialogBackgroundOutEase.getIsFinished())
        {
            this.dialogBackgroundOutEase.Update(gc, delta);
            this.dialogBackgroundYPosition = (int)this.dialogBackgroundOutEase.GetCurrentValue();
            formattingAnimationInProgress = true;
        }
        else if (this.dialogBackgroundOutEase.getIsFinished())
        {
            // If the dialog background out animation has finished,
            // then this encounter as a whole is finished too.
            this.setIsFinished(true);
            this.dialogBackgroundYPosition = (int)this.dialogBackgroundOutEase.GetCurrentValue();
            formattingAnimationInProgress = true;
        }
        else
        {
            this.dialogBackgroundYPosition = 0;
        }

        if (this.backgroundOpacityInEase.getIsStarted() && !this.backgroundOpacityInEase.getIsFinished())
        {
            this.backgroundOpacityInEase.Update(gc, delta);
            this.backgroundOpacityAlphaValue = (int)this.backgroundOpacityInEase.GetCurrentValue();
        }
        else if (this.backgroundOpacityOutEase.getIsStarted())
        {
            this.backgroundOpacityOutEase.Update(gc, delta);
            this.backgroundOpacityAlphaValue = (int)this.backgroundOpacityOutEase.GetCurrentValue();
        }
        else
        {
            this.backgroundOpacityAlphaValue = 255;
        }

        this.leftCharacterInEase.Update(gc, delta);
        this.leftCharacterOutEase.Update(gc, delta);
        this.rightCharacterInEase.Update(gc, delta);
        this.rightCharacterOutEase.Update(gc, delta);
        
        Case.getInstance().getDialogCharacterManager().UpdateForState(this.state, gc, delta);

        // If a formatting animation is in progress, we want to ignore any mouse clicks.
        if (formattingAnimationInProgress)
        {
            MouseHelper.HandleClick();
        }

        if (this.evidenceSelector.getIsShowing())
        {
            this.evidenceSelector.Update(gc, delta);

            if (!this.evidenceSelector.getIsShowing())
            {
                if (this.lastButtonArrayBeforeConversation.getCount() > 0)
                {
                    this.nextButtonArray = this.lastButtonArrayBeforeConversation;
                }
                else
                {
                    this.nextButtonArray = this.mainMenuButtonArray;
                }

                this.SwapButtonArrays();
            }
        }
        else if (this.currentConversation != null && this.dialogBackgroundInEase.getIsFinished())
        {
            if (state.getCurrentAnimation() != null)
            {
                state.getCurrentAnimation().Update(gc, delta);
            }

            if (state.getLeftCharacterXOffsetEasingFunction() != null)
            {
                state.getLeftCharacterXOffsetEasingFunction().Update(gc, delta);
            }

            if (state.getRightCharacterXOffsetEasingFunction() != null)
            {
                state.getRightCharacterXOffsetEasingFunction().Update(gc, delta);
            }

            this.currentConversation.Update(gc, delta);

            if (this.currentConversation.getIsFinished() && !formattingAnimationInProgress)
            {
                boolean shouldRunPresentWrongEvidenceConversation = this.currentConversation.getState().getPresentWrongEvidenceRequested();
                
                this.state = this.currentConversation.getState();
                this.state.ResetForConversation();

                if (this.currentConversation != this.getOneShotConversation())
                {
                    if (shouldRunPresentWrongEvidenceConversation && this.presentWrongEvidenceConversation != null)
                    {
                        this.currentConversation = this.presentWrongEvidenceConversation;
                        this.currentConversation.Begin(this.state);
                    }
                    else
                    {
                        this.currentConversation = null;
                        this.RefreshButtonArrayContents();

                        if (this.lastButtonArrayBeforeConversation.getCount() > 0)
                        {
                            this.nextButtonArray = this.lastButtonArrayBeforeConversation;
                        }
                        else
                        {
                            this.nextButtonArray = this.mainMenuButtonArray;
                        }

                        this.SwapButtonArrays();
                    }
                }
                else
                {
                    this.Close();
                }
            }
        }
        else if (this.currentConversation == null)
        {
            if (this.currentButtonArray != null)
            {
                if (this.shouldCloseButtonArray)
                {
                    this.currentButtonArray.Close();
                    this.shouldCloseButtonArray = false;
                }

                this.currentButtonArray.Update(gc,delta);

                if (this.currentButtonArray.getIsClosed())
                {
                    if (this.nextConversation != null)
                    {
                        this.BeginNextConversation();
                    }
                    else
                    {
                        this.SwapButtonArrays();

                        // If the current button array is null,
                        // that means we should show the 
                        // evidence selector.
                        if (this.currentButtonArray == null)
                        {
                            this.evidenceSelector.Begin();
                            this.evidenceSelector.Show();
                        }
                    }
                }

                if (this.currentButtonArray == this.mainMenuButtonArray && !this.evidenceSelector.getIsShowing())
                {
                    this.exitTab.Update();

                    if (this.exitTab.getIsClicked())
                    {
                        this.Close();
                    }
                    
                    this.presentEvidenceTab.Update();
                    
                    if (this.presentEvidenceTab.getIsClicked())
                    {
                        this.PrepNextButtonArray(null, -1);
                    }
                }
            }
        }
    }

    public void Draw(GameContainer gc, Graphics g) throws SlickException
    {
        RenderThread.getInstance().AddImageToRenderQueue(backgroundDarkeningTexture, 0, 0, new Color(255, 255, 255, backgroundOpacityAlphaValue));
        Case.getInstance().getDialogCharacterManager().DrawForState(this.state, gc, g);

        if (state.getCurrentAnimation() != null)
        {
            state.getCurrentAnimation().Draw(gc, g);
        }

        RenderThread.getInstance().AddImageToRenderQueue(dialogBackgroundTexture, 0, this.dialogBackgroundYPosition);
        
        if (this.evidenceSelector.getIsShowing())
        {
            this.evidenceSelector.Draw(gc, g, this.dialogBackgroundYPosition);
        }
        else if (this.currentConversation != null)
        {
            this.currentConversation.Draw(gc, g, this.dialogBackgroundYPosition);
        }
        else if (this.currentButtonArray != null)
        {
            this.currentButtonArray.Draw(gc, g, this.dialogBackgroundYPosition);
        }

        if (this.currentButtonArray == this.mainMenuButtonArray && !this.evidenceSelector.getIsShowing() && this.currentConversation == null)
        {
            this.exitTab.Draw(gc, g, this.dialogBackgroundYPosition);
            this.presentEvidenceTab.Draw(gc, g, this.dialogBackgroundYPosition);
        }
    }

    public void Reset()
    {
        this.exitTab.Reset();
        this.presentEvidenceTab.Reset();

        this.backgroundOpacityInEase.Reset();
        this.dialogBackgroundInEase.Reset();
        this.leftCharacterInEase.Reset();
        this.rightCharacterInEase.Reset();
        this.backgroundOpacityOutEase.Reset();
        this.dialogBackgroundOutEase.Reset();
        this.leftCharacterOutEase.Reset();
        this.rightCharacterOutEase.Reset();
        
        ButtonArrayEventProvider.ClearListener(this);
        EvidenceSelectorEventProvider.ClearListener(this);
        
        this.shouldCloseButtonArray = false;
    }

    private void RefreshButtonArrays()
    {
        this.RefreshButtonArrayContents();

        if (this.mainMenuButtonArray.getCount() >= 1)
        {
            this.nextButtonArray = this.mainMenuButtonArray;
            this.SwapButtonArrays();
        }
        else
        {
            throw new IllegalStateException("Encounter must have at least one line of dialog.");
        }
    }

    private void RefreshButtonArrayContents()
    {
        ArrayList<ButtonArrayLoadParameters> loadParametersList = new ArrayList<ButtonArrayLoadParameters>();

        for (int i = 0; i < this.conversationList.size(); i++)
        {
            Conversation conversation = this.conversationList.get(i);
            
            if (conversation.getIsEnabled() && !conversation.getHasBeenUnlocked() && (conversation.getRequiredPartnerId() == null || !conversation.getHasBeenCompleted()))
            {
                ButtonArrayLoadParameters loadParameters = new ButtonArrayLoadParameters();
                
                loadParameters.text = conversation.getName();
                loadParameters.showCheckBox = conversation.getHasBeenCompleted();

                if (conversation.getIsLocked() || (conversation.getRequiredPartnerId() != null && conversation.getWrongPartnerUsed() && Case.getInstance().getPartnerManager().GetPartnerFromId(conversation.getRequiredPartnerId()) != null))
                {
                    loadParameters.showLock = true;
                }
                
                loadParametersList.add(loadParameters);
            }
        }

        for (int i = 0; i < this.interrogationList.size(); i++)
        {
            Interrogation interrogation = this.interrogationList.get(i);
            
            if (!interrogation.getHasBeenCompleted())
            {
                if (interrogation.getIsEnabled())
                {
                    ButtonArrayLoadParameters loadParameters = new ButtonArrayLoadParameters();
                
                    loadParameters.text = interrogation.getName() + " (Interrogation)";

                    if (interrogation.getRequiredPartnerId() != null && interrogation.getWrongPartnerUsed() && Case.getInstance().getPartnerManager().GetPartnerFromId(interrogation.getRequiredPartnerId()) != null)
                    {
                        loadParameters.showLock = true;
                    }
                    
                    loadParametersList.add(loadParameters);
                }
            }
        }

        for (int i = 0; i < this.confrontationList.size(); i++)
        {
            Confrontation confrontation = this.confrontationList.get(i);
            
            if (!confrontation.getHasBeenCompleted())
            {
                if (confrontation.getIsEnabled())
                {
                    ButtonArrayLoadParameters loadParameters = new ButtonArrayLoadParameters();
                
                    loadParameters.text = confrontation.getName() + " (Confrontation)";

                    if (confrontation.getRequiredPartnerId() != null && confrontation.getWrongPartnerUsed() && Case.getInstance().getPartnerManager().GetPartnerFromId(confrontation.getRequiredPartnerId()) != null)
                    {
                        loadParameters.showLock = true;
                    }

                    loadParametersList.add(loadParameters);
                }
            }
        }

        this.mainMenuButtonArray.Load(loadParametersList);
        this.presentEvidenceTab.setIsEnabled(Case.getInstance().getEvidenceManager().getHasEvidence());
    }

    private void PrepNextButtonArray(ButtonArray nextButtonArray, int buttonClickedId)
    {
        this.nextButtonArray = nextButtonArray;

        if (buttonClickedId != -1)
        {
            this.currentButtonArray.ReorderOutAnimations(buttonClickedId);
        }

        this.shouldCloseButtonArray = true;
    }

    private void SwapButtonArrays()
    {
        if (this.nextButtonArray == null)
        {
            // Save away the current button array here if the next button array is null -
            // we want to return to the current button array, not the temporary null array.
            this.lastButtonArrayBeforeConversation = this.currentButtonArray;
        }

        this.currentButtonArray = this.nextButtonArray;
        this.nextButtonArray = null;

        if (this.currentButtonArray != null)
        {
            this.currentButtonArray.Show();
        }
    }

    private void BeginConversation(Conversation conversation)
    {
        this.currentConversation = conversation;
        this.currentConversation.Begin(this.state);
    }

    private void PrepNextConversation(Conversation nextConversation, int buttonClickedId)
    {
        this.nextConversation = nextConversation;
        this.currentButtonArray.ReorderOutAnimations(buttonClickedId);

        if (this.currentButtonArray != null)
        {
            this.lastButtonArrayBeforeConversation = this.currentButtonArray;
        }

        this.shouldCloseButtonArray = true;
    }

    private void BeginNextConversation()
    {
        this.currentConversation = this.nextConversation;
        this.nextConversation = null;
        this.currentConversation.Begin(this.state);
    }
    
    public void OnButtonArrayButtonClicked(ButtonArray sender, int id)
    {
        if (sender == this.mainMenuButtonArray)
        {
            this.OnMainMenuButtonClicked(id);
        }
    }

    private void OnMainMenuButtonClicked(int id)
    {
        int originalId = id;
        
        // No buttons are in the list for conversations that aren't available,
        // so we want to bump up the ID to account for these.
        for (int i = 0; i <= id; i++)
        {   
            Conversation conversation = this.allConversationList.get(i);
            
            if (!conversation.getIsEnabled() ||
                    conversation.getHasBeenUnlocked() ||
                    (conversation.getRequiredPartnerId() != null && conversation.getHasBeenCompleted()) ||
                    ((conversation instanceof Interrogation || conversation instanceof Confrontation) && conversation.getHasBeenCompleted()))
            {
                id++;
            }
        }

        this.PrepNextConversation(this.allConversationList.get(id), originalId);
    }
    
    public void OnButtonArrayCanceled(ButtonArray sender)
    {
        // Nothing to do here - no button array is cancelable.
    }

    public void OnEvidenceSelectorEvidencePresented(EvidenceSelector sender, String evidenceId)
    {
        Conversation conversationToUse = null;
        
        if (sender != this.evidenceSelector)
        {
            return;
        }

        if (this.presentEvidenceConversationDictionary.containsKey(evidenceId))
        {
            conversationToUse = this.presentEvidenceConversationDictionary.get(evidenceId);
        }
        else
        {
            conversationToUse = this.getPresentWrongEvidenceConversation();
        }

        if (this.currentButtonArray != null)
        {
            this.lastButtonArrayBeforeConversation = this.currentButtonArray;
        }

        this.BeginConversation(conversationToUse);
    }

    private void InitializeEasingFunctions()
    {
        this.backgroundOpacityInEase = new LinearEase(0, 255, 250);
        this.dialogBackgroundInEase = new QuadraticEase(Dialog.Height + Tab.Height - 3, 0, 250);
        this.leftCharacterInEase = new QuadraticEase(-Settings.DisplayBounds.getX() / 2, 0, 250);
        this.leftCharacterInEase.setAnimationStartDelay(250);
        this.rightCharacterInEase = new QuadraticEase(Settings.DisplayBounds.getX() / 2, 0, 250);
        this.rightCharacterInEase.setAnimationStartDelay(250);
        this.backgroundOpacityOutEase = new LinearEase(255, 0, 250);
        this.backgroundOpacityOutEase.setAnimationStartDelay(250);
        this.dialogBackgroundOutEase = new QuadraticEase(0, Dialog.Height + Tab.Height - 3, 250);
        this.dialogBackgroundOutEase.setAnimationStartDelay(250);
        this.leftCharacterOutEase = new QuadraticEase(0, -Settings.DisplayBounds.getX() / 2, 250);
        this.rightCharacterOutEase = new QuadraticEase(0, Settings.DisplayBounds.getX() / 2, 250);
    }

    private void Close()
    {
        this.backgroundOpacityOutEase.Begin();
        this.dialogBackgroundOutEase.Begin();
        this.leftCharacterOutEase.Begin();
        this.rightCharacterOutEase.Begin();

        this.state.setLeftCharacterXOffsetEasingFunction(this.leftCharacterOutEase);
        this.state.setRightCharacterXOffsetEasingFunction(this.rightCharacterOutEase);
    }

    public void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("Encounter");
        
        if (this.id != null)
        {
            writer.WriteTextElement("Id", this.id);
        }
        
        if (this.initialLeftCharacterId != null)
        {
            writer.WriteTextElement("InitialLeftCharacterId", this.initialLeftCharacterId);
        }
        
        if (this.initialLeftCharacterEmotionId != null)
        {
            writer.WriteTextElement("InitialLeftCharacterEmotionId", this.initialLeftCharacterEmotionId);
        }
        
        if (this.initialRightCharacterId != null)
        {
            writer.WriteTextElement("InitialRightCharacterId", this.initialRightCharacterId);
        }
        
        if (this.initialRightCharacterEmotionId != null)
        {
            writer.WriteTextElement("InitialRightCharacterEmotionId", this.initialRightCharacterEmotionId);
        }
        
        if (this.oneShotConversation != null)
        {
            writer.StartElement("OneShotConversation");
            this.oneShotConversation.SaveToXml(writer);
            writer.EndElement();
        }
        
        if (this.presentWrongEvidenceConversation != null)
        {
            writer.StartElement("PresentWrongEvidenceConversation");
            this.presentWrongEvidenceConversation.SaveToXml(writer);
            writer.EndElement();
        }
        
        if (this.presentWrongProfileConversation != null)
        {
            writer.StartElement("PresentWrongProfileConversation");
            this.presentWrongProfileConversation.SaveToXml(writer);
            writer.EndElement();
        }
        
        if (this.initialConversationId != null)
        {
            writer.WriteTextElement("InitialConversationId", this.initialConversationId);
        }
        
        if (this.oneShotConversationId != null)
        {
            writer.WriteTextElement("OneShotConversationId", this.oneShotConversationId);
        }
        
        writer.StartElement("ConversationList");
        
        for (int i = 0; i < this.conversationList.size(); i++)
        {
            writer.StartElement("Entry");
            writer.WriteTextElement("ConversationId", this.conversationList.get(i).getId());
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("InterrogationList");
        
        for (int i = 0; i < this.interrogationList.size(); i++)
        {
            writer.StartElement("Entry");
            writer.WriteTextElement("InterrogationId", this.interrogationList.get(i).getId());
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("ConfrontationList");
        
        for (int i = 0; i < this.confrontationList.size(); i++)
        {
            writer.StartElement("Entry");
            writer.WriteTextElement("ConfrontationId", this.confrontationList.get(i).getId());
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("PresentEvidenceConversationDictionary");
        String[] evidenceIds = this.presentEvidenceConversationDictionary.keySet().toArray(new String[0]);
        
        for (int i = 0; i < evidenceIds.length; i++)
        {
            writer.StartElement("Entry");
            String evidenceId = evidenceIds[i];
            writer.WriteTextElement("EvidenceId", evidenceId);
            this.presentEvidenceConversationDictionary.get(evidenceId).SaveToXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.EndElement();
    }

    public Encounter(CaseXmlReader reader)
    {
        this.conversationList = new ArrayList<Conversation>();
        this.interrogationList = new ArrayList<Interrogation>();
        this.confrontationList = new ArrayList<Confrontation>();
        this.allConversationList = new ArrayList<Conversation>();
        this.presentEvidenceConversationDictionary = new HashMap<String, Conversation>();

        this.mainMenuButtonArray = new ButtonArray(MainMenuHeaderText);
        this.currentButtonArray = this.mainMenuButtonArray;

        this.exitTab = new Tab((int)Settings.DisplayBounds.getX() - Tab.Width, true /* isClickable */, ExitText);
        this.presentEvidenceTab = new Tab((int)Settings.DisplayBounds.getX() - 2 * Tab.Width - 7, true /* isClickable */, PresentEvidenceText);

        this.InitializeEasingFunctions();
        
        reader.StartElement("Encounter");
        
        if (reader.ElementExists("Id"))
        {
            this.id = reader.ReadTextElement("Id");
        }
        
        if (reader.ElementExists("InitialLeftCharacterId"))
        {
            this.initialLeftCharacterId = reader.ReadTextElement("InitialLeftCharacterId");
        }
        
        if (reader.ElementExists("InitialRightCharacterId"))
        {
            this.initialRightCharacterId = reader.ReadTextElement("InitialRightCharacterId");
        }
        
        if (reader.ElementExists("OneShotConversation"))
        {
            reader.StartElement("OneShotConversation");
            this.oneShotConversation = Conversation.LoadFromXml(reader);
            reader.EndElement();
        }
        
        if (reader.ElementExists("PresentWrongEvidenceConversation"))
        {
            reader.StartElement("PresentWrongEvidenceConversation");
            this.presentWrongEvidenceConversation = Conversation.LoadFromXml(reader);
            reader.EndElement();
        }
        
        reader.StartElement("ConversationList");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            String conversationId = reader.ReadTextElement("ConversationId");
            Conversation conversation = Case.getInstance().getContent().GetConversationFromId(conversationId);
            this.conversationList.add(conversation);
            this.allConversationList.add(conversation);
        }
        
        reader.EndElement();
        
        reader.StartElement("InterrogationList");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            String interrogationId = reader.ReadTextElement("InterrogationId");
            Interrogation interrogation = (Interrogation)Case.getInstance().getContent().GetConversationFromId(interrogationId);
            this.interrogationList.add(interrogation);
            this.allConversationList.add(interrogation);
        }
        
        reader.EndElement();
        
        reader.StartElement("ConfrontationList");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            String confrontationId = reader.ReadTextElement("ConfrontationId");
            Confrontation confrontation = (Confrontation)Case.getInstance().getContent().GetConversationFromId(confrontationId);
            this.confrontationList.add(confrontation);
            this.allConversationList.add(confrontation);
        }
        
        reader.EndElement();
        
        reader.StartElement("PresentEvidenceConversationDictionary");
        reader.StartList("Entry");
        
        while (reader.MoveToNextListItem())
        {
            String evidenceId = reader.ReadTextElement("EvidenceId");
            Conversation conversation = Conversation.LoadFromXml(reader);
            
            this.presentEvidenceConversationDictionary.put(evidenceId, conversation);
        }
        
        reader.EndElement();
        
        reader.EndElement();
    }

    public void markChildSprites(String markParent) throws CaseParseException
    {
        if (this.getInitialLeftCharacterId() != null)
        {
            DialogCharacter d = Case.getInstance().getDialogCharacterManager().GetCharacterFromId(this.getInitialLeftCharacterId());
            d.markChildSprites(markParent, this.initialLeftCharacterEmotionId);
        }
        
        if (this.getInitialRightCharacterId() != null)
        {
            DialogCharacter d = Case.getInstance().getDialogCharacterManager().GetCharacterFromId(this.getInitialRightCharacterId());
            d.markChildSprites(markParent, this.initialRightCharacterEmotionId);
        }
        
        for (Conversation c : this.conversationList)
        {
            c.markChildSprites(markParent);
        }
        
        for (Conversation c : this.interrogationList)
        {
            c.markChildSprites(markParent);
        }
        
        for (Conversation c : this.confrontationList)
        {
            c.markChildSprites(markParent);
        }
        
        for (Conversation c : this.presentEvidenceConversationDictionary.values())
        {
            c.markChildSprites(markParent);
        }
        
        if (this.oneShotConversation != null)
        {
            this.oneShotConversation.markChildSprites(markParent);
        }
        
        if (this.presentWrongEvidenceConversation != null)
        { 
            this.presentWrongEvidenceConversation.markChildSprites(markParent);
        }
        
        if (this.presentWrongProfileConversation != null)
        { 
            this.presentWrongProfileConversation.markChildSprites(markParent);
        }
    }
}

